﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using ORM.Business.Feedbacks;
using ORM.Business.Interfaces;
using ORM.Business.Models.Entities;
using ORM.Business.Models;
using ORM.Resources;
using ORM.Common.Logging;

namespace ORM.Business.Repositories
{
    public class CommentRepository :ICommentRepository
    {
        public CommentListFeedback GetAllComments(int currentUserId, int guideId, PageInfo pageInfo)
        {
            try
            {
                using(var ORMDbContext = new OrmEntities())
                {
                    var Comments = new List<GuideComment>();
                    var query = (from a in ORMDbContext.GuideComments
                                 join u2 in ORMDbContext.Users on a.PostedBy equals u2.Id
                                 join g in ORMDbContext.Guides on a.GuideId equals g.Id
                                 orderby a.PostedDate descending
                                 where !a.IsDeleted && !g.IsDeleted && a.GuideId == guideId
                                 select new
                                 {
                                     CommentId = a.Id,
                                     CommentContentHtml = a.ContentHtml,
                                     CommentPostedBy = a.PostedBy,
                                     CommentPostedDate = a.PostedDate,
                                     CommentDownVotes = a.DownVotes,
                                     CommentUpVotes = a.UpVotes,
                                     CommentUsername = u2.Username,
                                     commentLastUpdate=a.LastUpdate,
                                     CommentAvatarUrl = u2.AvatarUrl,
                                     a.IsReadByGuideAuthor,
                                 });

                    var guide = ORMDbContext.Guides.FirstOrDefault(t => t.Id == guideId);
                    if (guide == null)
                        return new CommentListFeedback(false, Messages.QuestionNotExisted);
                    var total = guide.Comments;

                    query = query.Skip((pageInfo.PageNo - 1) * pageInfo.PageSize).Take(pageInfo.PageSize);
                    foreach (var q in query)
                    {
                        var commentVote = ORMDbContext.VotedGuideComments.SingleOrDefault(t => t.CommentId == q.CommentId && t.VotedById == currentUserId);
                        bool isVotedByCurrentUser = commentVote != null;
                        var answerReport = ORMDbContext.ReportedGuideComments.SingleOrDefault(t => t.CommentId == q.CommentId && t.ReportedById == currentUserId);
                        bool isReportedByCurrentUser = answerReport != null;
                        bool highLight = false;
                        if (currentUserId == guide.PostedBy && currentUserId != q.CommentPostedBy)
                        {
                            highLight = !q.IsReadByGuideAuthor;
                            var comment = ORMDbContext.GuideComments.Find(q.CommentId);
                            comment.IsReadByGuideAuthor = true;
                        }
                        Comments.Add(new GuideComment
                        {
                            Id = q.CommentId,
                            ContentHtml = q.CommentContentHtml,
                            PostedBy = q.CommentPostedBy,
                            PostedDate = q.CommentPostedDate,
                            PostBy = new user { Id = q.CommentPostedBy, Username = q.CommentUsername, AvatarUrl = q.CommentAvatarUrl },
                            GuideId = guideId,
                            UpVotes = q.CommentUpVotes,
                            DownVotes = q.CommentDownVotes,
                            LastUpdate = q.commentLastUpdate,
                            // IsAccepted = q.,
                            IsVotedByCurrentUser = isVotedByCurrentUser,
                            IsReportedByCurrentUser = isReportedByCurrentUser,
                            Highlight = highLight,
                        });
                    }
                    ORMDbContext.SaveChanges();
                    return new CommentListFeedback(true, null, Comments, total);
                }
                

            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new CommentListFeedback(false, Messages.GeneralError);
            }
        }
        public CommentListFeedback GetHighScoreComments(int currentUserId, int guideId, PageInfo pageInfo)
        {
            try
            {
                using (var ORMDbContext = new OrmEntities())
                {
                    var comments = new List<GuideComment>();
                    var query = (from a in ORMDbContext.GuideComments
                                 join u2 in ORMDbContext.Users on a.PostedBy equals u2.Id
                                 join q in ORMDbContext.Guides on a.GuideId equals q.Id
                                 orderby a.UpVotes descending
                                 where !a.IsDeleted && !q.IsDeleted && a.GuideId == guideId
                                 select new
                                 {
                                     CommentId = a.Id,
                                     CommentContentHtml = a.ContentHtml,
                                     CommentPostedBy = a.PostedBy,
                                     CommentPostedDate = a.PostedDate,
                                     CommentDownVotes = a.DownVotes,
                                     CommentUpVotes = a.UpVotes,
                                     commentLastUpdate=a.LastUpdate,
                                     CommentUsername = u2.Username,
                                     AvatarUrl = u2.AvatarUrl,
                                 });

                    var guide = ORMDbContext.Guides.FirstOrDefault(t => t.Id == guideId);
                    if (guide == null)
                        return new CommentListFeedback(false, Messages.QuestionNotExisted);
                    var total = guide.Comments;

                    query = query.Skip((pageInfo.PageNo - 1) * pageInfo.PageSize).Take(pageInfo.PageSize);
                    foreach (var q in query)
                    {
                        var commentVote = ORMDbContext.VotedGuideComments.SingleOrDefault(t => t.CommentId == q.CommentId && t.VotedById == currentUserId);
                        bool isVotedByCurrentUser = commentVote != null;
                        var answerReport = ORMDbContext.ReportedGuideComments.SingleOrDefault(t => t.CommentId == q.CommentId && t.ReportedById == currentUserId);
                        bool isReportedByCurrentUser = answerReport != null;
                        comments.Add(new GuideComment
                        {
                            Id = q.CommentId,
                            ContentHtml = q.CommentContentHtml,
                            PostedBy = q.CommentPostedBy,
                            PostedDate = q.CommentPostedDate,
                            PostBy = new user { Id = q.CommentPostedBy, Username = q.CommentUsername, AvatarUrl = q.AvatarUrl},
                           GuideId = guideId,
                            UpVotes = q.CommentUpVotes,
                            DownVotes = q.CommentDownVotes,
                            LastUpdate=q.commentLastUpdate,
                           // IsAccepted = q.,
                            IsVotedByCurrentUser = isVotedByCurrentUser,
                            IsReportedByCurrentUser = isReportedByCurrentUser,
                        });
                    }

                    return new CommentListFeedback(true, null, comments, total);
                }


            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new CommentListFeedback(false, Messages.GeneralError);
            }
        }


        public Feedback<GuideComment> InsertComment(GuideComment a)
        {
            var Comment = new GuideComment
            {
                GuideId = a.GuideId,
                ContentHtml = a.ContentHtml,
                PostedBy = a.PostedBy,
                PostedDate = DateTime.Now,
                ContentText="contenttext",
                LastUpdate = DateTime.Now,
                UpdatedBy = null,
                IsDeleted = false,
                Reports=0,
                UpVotes=0,
                DownVotes=0,
                IsReadByGuideAuthor = false,
            };
            try
            {
                using (var ORMDbContext = new OrmEntities())
                {
                    var guide = ORMDbContext.Guides.Single(t => t.Id == Comment.GuideId);
                    var count = ORMDbContext.GuideComments.Where(t => !t.IsDeleted && t.GuideId == Comment.GuideId).Count();
                    guide.Comments = count + 1;
                    // Add to DB
                    ORMDbContext.GuideComments.Add(Comment);
                    ORMDbContext.SaveChanges();
                    var user = ORMDbContext.Users.Where(t => t.Id == Comment.PostedBy).Select(t => new { t.Id,t.Username }).First();
                    Comment.PostBy = new user { Id = user.Id,Username = user.Username };
                    return new Feedback<GuideComment>(true, null, Comment);
                }

            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<GuideComment>(false, Messages.GeneralError);
            }
        }

        public Feedback<GuideComment> VoteComment(int commentId, int userId)
        {
            try
            {
                using (var ORMDbContext = new OrmEntities())
                {
                    var Comment = ORMDbContext.GuideComments.Single(i => i.Id == commentId);
                    var CommentVote = ORMDbContext.VotedGuideComments.SingleOrDefault(t => t.CommentId == commentId && t.VotedById == userId);

                    //Do not allow seft voting
                    if (Comment.PostedBy == userId)
                    {
                        return new Feedback<GuideComment>(false, Messages.VoteAnswer_SeftVoting, null);
                    }

                    //Already voted up --> Remove this vote
                    if (CommentVote != null)
                    {
                        ORMDbContext.VotedGuideComments.Remove(CommentVote);
                        Comment.UpVotes--;
                    }
                    //Not vote yet (Insert)
                    else
                    {
                        CommentVote = new VotedGuideComment()
                        {
                            IsUpVote = true,
                            CommentId = commentId,
                            VotedById = userId,
                            VotedDate = DateTime.Now,
                        };
                        ORMDbContext.VotedGuideComments.Add(CommentVote);
                        Comment.UpVotes++;
                    }

                    ORMDbContext.SaveChanges();

                    return new Feedback<GuideComment>(true, null, Comment);
                }

            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<GuideComment>(false, Messages.GeneralError);
            }
        }
        public Feedback<GuideComment> DeleteAnComment(int commentId)
        {
            try
            {
                using (var ORMDbContext = new OrmEntities())
                {
                    var comment = ORMDbContext.GuideComments.Single(i => i.Id == commentId);
                    comment.IsDeleted = true;
                    var guide = ORMDbContext.Guides.SingleOrDefault(g => !g.IsDeleted && g.Id == comment.GuideId);
                    guide.Comments --;
                    ORMDbContext.SaveChanges();
                    return new Feedback<GuideComment>(true, null, comment);
                }

            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<GuideComment>(false, Messages.GeneralError);
            }
        }
        #region Reported Comment
        public Feedback<GuideComment> ReportComment(int commentId, string reason, int userId)
        {
            try
            {
                using (var ORMDbContext = new OrmEntities())
                {
                    var comment = ORMDbContext.GuideComments.Single(i => i.Id == commentId);
                    var commentReport = ORMDbContext.ReportedGuideComments.SingleOrDefault(t => t.CommentId == commentId && t.ReportedById == userId);

                    //Already reported --> Remove this report
                    if (commentReport != null)
                    {
                        ORMDbContext.ReportedGuideComments.Remove(commentReport);
                        comment.Reports--;
                    }
                    //Not reported yet (Insert)
                    else
                    {
                        commentReport = new ReportedGuideComment()
                        {
                            CommentId = commentId,
                            Reason = reason,
                            ReportedById = userId,
                            ReportedDate = DateTime.Now,
                            IsIgnored = false,
                        };
                        ORMDbContext.ReportedGuideComments.Add(commentReport);
                        comment.Reports++;
                    }

                    ORMDbContext.SaveChanges();

                    return new Feedback<GuideComment>(true, null, comment);
                }

            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<GuideComment>(false, Messages.GeneralError);
            }
        }

        public Feedback<IList<GuideComment>> GetAllReportedComment(int minReportNumber)
        {
            try
            {
                using (var ORMDbContext = new OrmEntities())
                {
                    var query = from q in ORMDbContext.GuideComments
                                from u in ORMDbContext.Users
                                where !q.IsDeleted && q.Reports >= minReportNumber && q.PostedBy == u.Id
                                orderby q.Reports descending
                                select new
                                {
                                    q.Id,
                                    q.Reports,
                                    q.ContentHtml,
                                    q.PostedDate,
                                    q.PostedBy,
                                    u.Username
                                };
                    List<GuideComment> rq = new List<GuideComment>();
                    foreach (var q in query)
                    {
                        rq.Add(new GuideComment
                        {
                            Id = q.Id,
                            
                            ContentHtml = q.ContentHtml,
                            PostedDate = q.PostedDate,
                            Reports = q.Reports,
                            PostBy = new user
                            {
                                Id = q.PostedBy,
                                Username = q.Username
                            },
                        });
                    }

                    return new Feedback<IList<GuideComment>>(true, null, rq);
                }

            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<IList<GuideComment>>(false, Messages.GeneralError);
            }
        }

        public Feedback<IList<ReportedGuideComment>> GetReportedCommentDetails(int id)
        {
            try
            {
                using (var ORMDbContext = new OrmEntities())
                {
                    var query = ORMDbContext.ReportedGuideComments.Where(i => i.CommentId == id)
                        .Select(i => new
                        {
                            i.Id,
                            i.ReportedDate,
                            i.Reason,
                            i.ReportedBy.Username
                        });

                    List<ReportedGuideComment> rq = new List<ReportedGuideComment>();
                    foreach (var q in query)
                    {
                        rq.Add(new ReportedGuideComment
                        {
                            Id = q.Id,
                            ReportedDate = q.ReportedDate,
                            Reason = q.Reason,
                            ReportedBy = new user
                            {
                                Username = q.Username
                            }
                        });
                    }
                    return new Feedback<IList<ReportedGuideComment>>(true, null, rq);

                }

            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback<IList<ReportedGuideComment>>(false, Messages.GeneralError);
            }
        }

        public Feedback DeleteReportedComment(int id)
        {
            try
            {
                using (var ORMDbContext = new OrmEntities())
                {
                    GuideComment q = ORMDbContext.GuideComments.Single(i => i.Id == id);
                    q.IsDeleted = true;
                    var guide = ORMDbContext.Guides.SingleOrDefault(g => !g.IsDeleted && g.Id == q.GuideId);
                    guide.Comments--;
                    user User = ORMDbContext.Users.Find(q.PostedBy);
                    User.Ponit += KeyObject.PointConfig.Spam;
                    ORMDbContext.SaveChanges();

                    return new Feedback(true);
                }

            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback(false, Messages.GeneralError);
            }
        }

        public Feedback DeleteFalseReports(int id)
        {
            try
            {
                using (var ORMDbContext = new OrmEntities())
                {
                    // Delete attached reports of the quesion
                    List<ReportedGuideComment> rq = ORMDbContext.ReportedGuideComments.Where(i => i.CommentId == id).ToList();
                    foreach (ReportedGuideComment i in rq)
                    {
                        i.IsIgnored = true;
                    }
                    //set report number to zero
                    GuideComment q = ORMDbContext.GuideComments.Single(i => i.Id == id);
                    q.Reports = 0;
                    ORMDbContext.SaveChanges();

                    return new Feedback(true);
                }

            }
            catch (Exception e)
            {
                Logger.Error(e);
                return new Feedback(false, Messages.GeneralError);
            }
        }

        #endregion
    }

}
